#include "internal.h"
#include "SensorBase.h"
#include "SensorBase.tmh"

#include "RS232Target.h" // for SensorState
#include "WpdObjectProperties.h" 

SensorBase::SensorBase(WpdObjectProperties* pWpdObjectProperties)
{
	m_pWpdObjectProperties = pWpdObjectProperties;
}

SensorBase::~SensorBase(void)
{
	m_pWpdObjectProperties = NULL;
}


HRESULT SensorBase::GetPropertyValues(
    IPortableDeviceKeyCollection*  pKeys,
    IPortableDeviceValues*         pValues)
{
	HRESULT	hr		= S_OK;
    DWORD	cKeys   = 0;

	hr = pKeys->GetCount(&cKeys);
	if (hr == S_OK)
	{
		for (DWORD dwIndex = 0; dwIndex < cKeys; dwIndex++)
		{
			PROPERTYKEY Key = WPD_PROPERTY_NULL;
			hr = pKeys->GetAt(dwIndex, &Key);

			if (hr == S_OK)
			{
				// Preset the property value to 'error not supported'.  The actual value
				// will replace this value, if read from the device.
				pValues->SetErrorValue(Key, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));

				hr = OnGetPropertyValues(Key, pValues);
			}
		}
	}
	return hr;
}

/// This method will add values for common properties
HRESULT SensorBase::OnGetPropertyValues(PROPERTYKEY &Key, IPortableDeviceValues *pValues)
{
	HRESULT hr = S_OK;

	if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_TYPE))
	{
		hr = pValues->SetGuidValue(SENSOR_PROPERTY_TYPE, m_gdSensorType);
	}
	else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_STATE))
	{
		hr = pValues->SetUnsignedIntegerValue(SENSOR_PROPERTY_STATE,
			m_pWpdObjectProperties->m_pTarget->GetSensorState());//TODO: refactor
	}
	else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_PERSISTENT_UNIQUE_ID))
	{
		// This should not be hardcoded but must be CoCreated at Runtime the first time the driver is installed
		// and subsequently read from the device property store
		hr = pValues->SetGuidValue(SENSOR_PROPERTY_PERSISTENT_UNIQUE_ID, m_gdSensorUniqueId);
	}
    else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_MANUFACTURER))
    {
        hr = pValues->SetStringValue(SENSOR_PROPERTY_MANUFACTURER, DEVICE_MANUFACTURER_VALUE);
    }
    else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_MODEL))
    {
        hr = pValues->SetStringValue(SENSOR_PROPERTY_MODEL, DEVICE_MODEL_VALUE);
    }
    else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_SERIAL_NUMBER))
    {
        hr = pValues->SetStringValue(SENSOR_PROPERTY_SERIAL_NUMBER, DEVICE_SERIAL_NUMBER_VALUE);
    }
	else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_FRIENDLY_NAME))
	{
		hr = pValues->SetStringValue(SENSOR_PROPERTY_FRIENDLY_NAME, m_strSensorName);
	}
	else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_DESCRIPTION))
	{
		hr = pValues->SetStringValue(SENSOR_PROPERTY_DESCRIPTION, m_strSensorName);
	}
	else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_CONNECTION_TYPE))
	{
		hr = pValues->SetUnsignedIntegerValue(SENSOR_PROPERTY_CONNECTION_TYPE, SENSOR_CONNECTION_TYPE_PC_ATTACHED);
	}
	else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL))
	{
		hr = pValues->SetUnsignedIntegerValue(SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL,
			m_pWpdObjectProperties->GetSamplingRate());
	}
	else if (IsEqualPropertyKey(Key, SENSOR_PROPERTY_MIN_REPORT_INTERVAL))
	{
		hr = pValues->SetUnsignedIntegerValue(SENSOR_PROPERTY_MIN_REPORT_INTERVAL, SENSOR_UPDATE_INTERVAL_MIN);
	}
	else
	// Set general properties for sensor
	if (IsEqualPropertyKey(Key, WPD_OBJECT_ID))
	{
		hr = pValues->SetStringValue(WPD_OBJECT_ID, m_strSensorId);
	}
	else if (IsEqualPropertyKey(Key, WPD_FUNCTIONAL_OBJECT_CATEGORY))
	{
		hr = pValues->SetGuidValue(WPD_FUNCTIONAL_OBJECT_CATEGORY, m_gdSensorCategory); //
	}
	return hr;
}


HRESULT SensorBase::GetDataValues(
		IPortableDeviceKeyCollection*  pKeys,
		IPortableDeviceValues*         pValues)
{
    HRESULT hr		= S_OK;
    DWORD	cKeys   = 0;

	hr = pKeys->GetCount(&cKeys);
	if (hr == S_OK)
	{
	    for (DWORD dwIndex = 0; dwIndex < cKeys; dwIndex++)
        {
            PROPERTYKEY Key = WPD_PROPERTY_NULL;
            hr = pKeys->GetAt(dwIndex, &Key);

            if (hr == S_OK)
            {
                // Preset the property value to 'error not supported'.  The actual value
                // will replace this value, if read from the device.
                pValues->SetErrorValue(Key, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));

				if (IsEqualPropertyKey(Key, SENSOR_DATA_TYPE_TIMESTAMP))
				{                        
					// Convert timestamp value from FILETIME to PROPVARIANT 
					PROPVARIANT var;
					PropVariantInit( &var );

					var.vt                      = VT_FILETIME;
					var.filetime.dwLowDateTime  = m_ftLastUpdateTime.dwLowDateTime;
					var.filetime.dwHighDateTime = m_ftLastUpdateTime.dwHighDateTime;

					hr = pValues->SetValue(SENSOR_DATA_TYPE_TIMESTAMP, &var);

					// Free any allocated resources
					PropVariantClear( &var );
				}
				else 
				{
					// Call virtual method
					hr = OnGetDataValues(Key, pValues);
				}
            }
        }
	}
	return hr;
}

HRESULT SensorBase::OnGetDataValues(PROPERTYKEY &Key, IPortableDeviceValues *pValues)
{
	UNREFERENCED_PARAMETER(Key);
	UNREFERENCED_PARAMETER(pValues);
	return S_OK;
}

HRESULT SensorBase::UpdateTimeStamp()
{
    HRESULT hr = S_OK;

    //Get the current time in  SYSTEMTIME format
    SYSTEMTIME st;
    ::GetSystemTime(&st);

    // Convert the SYSTEMTIME into FILETIME
    FILETIME ft;
    if(FALSE == ::SystemTimeToFileTime(&st, &ft))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }

    if(S_OK == hr)
    {
		m_ftLastUpdateTime = ft;
    }

    return hr;
}

HRESULT SensorBase::UpdateSensorReading(
	LONGLONG llSensorReading)
{
	HRESULT hr = S_OK;
	m_llSensorReading = llSensorReading;
	
	hr = UpdateTimeStamp();
	if (S_OK == hr)
	{
		hr = OnUpdateSensorReading();
	}
	return hr;
}

HRESULT SensorBase::OnUpdateSensorReading()
{
	// this method can be overriden in derived class
	return S_OK;
}
